using System;
using System.Collections.Generic;
using System.Windows.Forms;
using AssetManagementSystem.Model;
using AssetManagementSystem.Presenter;
using AssetManagementSystem.Utils;
using AssetManagementSystem.Utils.Events;
using AssetManagementSystem.View.IView;

namespace AssetManagementSystem.View.Controls {
    public partial class ControlStudents : UserControl, IStudentView, ILoanView, IHoldView {

        Dictionary<string, Student> studentList;
        Dictionary<int, Loan> loanList;
        Dictionary<string, Asset> assetList;
        List<Hold> holdList;


        //==================================================
        // IStudentView Events
        //==================================================
        public event EventHandler Students_LoadAll;
        public event EventHandler<SearchEventArgs> Students_Find;
        public event EventHandler<StudentEventArgs> Student_Create;
        public event EventHandler<StudentEventArgs> Student_Update;
        public event EventHandler<StudentEventArgs> Student_Delete;
        //==================================================

        //==================================================
        // ILoanView Events
        //==================================================
        public event EventHandler Loans_LoadAll;
        public event EventHandler<SearchEventArgs> Loans_Find;
        public event EventHandler<LoanEventArgs> Loan_Create;
        public event EventHandler<LoanEventArgs> Loan_Return;
        public event EventHandler<LoanAssetEventArgs> LoanAsset_Return;
        public event EventHandler LoanAssets_LoadAvailable;
        public event EventHandler<LoanEventArgs> Loan_Notify;
        //==================================================

        //==================================================
        // IHoldView Events
        //==================================================
        public event EventHandler Holds_LoadAll;
        public event EventHandler<SearchEventArgs> Holds_Find;
        public event EventHandler<HoldEventArgs> Hold_Create;
        public event EventHandler<HoldEventArgs> Hold_Delete;
        //==================================================

        //==================================================
        // View Constructor
        //==================================================
        public ControlStudents() {
            InitializeComponent();
            studentList = new Dictionary<string, Student>();
            loanList = new Dictionary<int, Loan>();

            //Create a presenter to handle events and update display data
            StudentPresenter studentPresenter = new StudentPresenter(this);
            //fire event to request a list of all students
            this.Students_LoadAll.Invoke(this, new EventArgs());
            //Create loan presenter
            LoanPresenter loanPresenter = new LoanPresenter(this);
            //fire event to request a list of all loans
            this.Loans_LoadAll.Invoke(this, new EventArgs());
            //Create hold presenter
            HoldPresenter holdPresenter = new HoldPresenter(this);
            //fire event to request all holds
            this.Holds_LoadAll.Invoke(this, new EventArgs());
        }
        //==================================================

        public void RefreshAll() {
            this.Students_LoadAll.Invoke(this, new EventArgs());
            this.Loans_LoadAll.Invoke(this, new EventArgs());
            this.Holds_LoadAll.Invoke(this, new EventArgs());
        }

        //==================================================
        // IStudentView Methods
        //==================================================
        public void SetStudentList(List<Student> students) {
            this.studentList.Clear();
            foreach (Student student in students) {
                studentList.Add(student.StudentId, student);
            }
            RefreshStudentsDisplay();
        }
        //==================================================

        //==================================================
        // ILoanView Methods
        //==================================================
        public void SetLoanList(List<Loan> loans) {
            this.loanList.Clear();
            foreach (Loan loan in loans) {
                if (!loan.IsReturned()) {
                    loanList.Add(loan.Id, loan);
                }
            }
            lstStudents_SelectedIndexChanged(lstStudents, new EventArgs());
        }
        public void SetAvailableAssets(List<Asset> assets) {
            //unused 
        }
        //==================================================

        //==================================================
        // IHoldView Methods
        //==================================================
        public void SetHoldList(List<Hold> holds) {
            this.holdList = holds;
            lstStudents_SelectedIndexChanged(lstStudents, new EventArgs());
        }
        //==================================================

        //==================================================
        // Shared Interface Methods
        //==================================================
        public void ShowMessage(string message) {
            MessageBox.Show(message);
        }
        //==================================================

        public void RefreshLoansDisplay() {
            gridSelectedStudentsLoans.Rows.Clear();
            if (lstStudents.SelectedIndex > -1) {
                string studentId = lstStudents.SelectedItem.ToString();
                foreach (KeyValuePair<int, Loan> loan in loanList) {
                    if (loan.Value.StudentId == studentId) {
                        string loanDays = loan.Value.GetDaysLeft().ToString();
                        if (loan.Value.IsOverdue()) {
                            loanDays = "Overdue";
                        } else if(loan.Value.IsReturned()) {
                            loanDays = "Returned";
                        }
                        gridSelectedStudentsLoans.Rows.Add(loan.Key.ToString(), loan.Value.StartDate.ToString("dd/MM/yyyy"), loan.Value.DueDate.ToString("dd/MM/yyyy"), loan.Value.Assets.Count, loanDays);
                    }
                }
            }
        }

        public void RefreshLoanAssetsDisplay() {
            gridSelectedLoansAssets.Rows.Clear();
            if (gridSelectedStudentsLoans.Rows.GetRowCount(DataGridViewElementStates.Selected) > 0) {
                foreach(KeyValuePair<string, DateTime> loanAsset in loanList[Convert.ToInt32(gridSelectedStudentsLoans.SelectedRows[0].Cells["LoanNo"].Value)].Assets){
                    string status = "Returned: " + loanAsset.Value.ToString("dd/MM/yyyy");
                    if(loanAsset.Value == DateTime.MinValue){
                        status = "On Loan";
                    }
                    gridSelectedLoansAssets.Rows.Add(loanAsset.Key.ToString(), status);
                }
            }
        }

        public void RefreshHoldsDisplay() {
            gridHold.Rows.Clear();
            if (lstStudents.SelectedIndex > -1) {
                string studentId = lstStudents.SelectedItem.ToString();
                foreach (Hold hold in holdList) {
                    if (hold.StudentId == studentId) {
                        string status = "Available";
                        if (!hold.IsAvailable)
                            status = "Due Back: " + hold.DueBack.ToString("dd/MM/yyyy");
                        gridHold.Rows.Add(
                            hold.AssetId, 
                            hold.DateCreated.ToString("dd/MM/yyyy"),
                            status
                            );
                    }
                }
            }
        }


        ////TO DO - Start Using these
        //public void setStudent_SelectedLoansAssets(List<Asset> assets) {
        //    selectedLoansAssets = assets;
        //    refreshStudent_AssetDisplay();
        //}

        

        /// <summary>
        /// Clears the displayed list of students and reloads them from the student list
        /// </summary>
        public void RefreshStudentsDisplay() {
            lstStudents.Items.Clear();
            foreach (KeyValuePair<string, Student> student in studentList) {
                lstStudents.Items.Add(student.Key);
            }
        }

        /// <summary>
        /// Displays the details of the currently selected student
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstStudents_SelectedIndexChanged(object sender, EventArgs e) {
            if (lstStudents.Items.Count > 0 && lstStudents.SelectedIndex >= 0) {
                //If a student has been selected, show their detail and disable editing
                DisplayStudentDetails(studentList[lstStudents.SelectedItem.ToString()]);
                AllowEditStudent(false);
            } else {
                DisplayStudentDetails(null);
            }
            RefreshLoansDisplay();
            RefreshHoldsDisplay();
        }

        /// <summary>
        /// Fires the student search event when the search button is clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSearch_Click(object sender, EventArgs e) {
            this.Students_Find(this, new SearchEventArgs(txtSearch.Text, "Student"));
        }

        /// <summary>
        /// Fires the search event when the 'Enter' key is clicked in the search textbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtSearch_KeyDown(object sender, KeyEventArgs e) {
            //perform search when enter key is pressed
            if (e.KeyCode == Keys.Enter) {
                this.Students_Find.Invoke(this, new SearchEventArgs(txtSearch.Text, "Student"));
            }
        }

        /// <summary>
        /// Handles click events for the button that toggles student details editing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnToggleEditStudent_Click(object sender, EventArgs e) {
            if (btnEditStudent.Text == "Edit" && txtStudentNumber.Text != "") {
                AllowEditStudent(true);
            } else {
                //fire the list selection change event to reload selected student details
                lstStudents_SelectedIndexChanged(lstStudents, e);
            }
        }

        /// <summary>
        /// Toggles allowing editing of the currently displayed student's details
        /// </summary>
        /// <param name="allow">True - Student details can be edited</param>
        private void AllowEditStudent(bool allow) {
            txtStudentFName.Enabled = allow;
            txtStudentLName.Enabled = allow;
            txtStudentEmail.Enabled = allow;
            btnSave.Enabled = allow;
            if (allow) {
                btnEditStudent.Text = "Cancel";
            } else {
                btnEditStudent.Text = "Edit";
            }
        }

        /// <summary>
        /// Displays the details of single student on the view
        /// </summary>
        /// <param name="student">The student details to display</param>
        public void DisplayStudentDetails(Student student) {
            if (student != null) {
                txtStudentFName.Text = student.FirstName;
                txtStudentLName.Text = student.LastName;
                txtStudentNumber.Text = student.StudentId;
                txtStudentEmail.Text = student.EmailAddress;
            } else {
                txtStudentFName.Text = "";
                txtStudentLName.Text = "";
                txtStudentNumber.Text = "";
                txtStudentEmail.Text = "";
            }
        }

        /// <summary>
        /// Saves the updated details for the currently displayed student
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSave_Click(object sender, EventArgs e) {
            //Update the student in the model
            this.Student_Update.Invoke(this, new StudentEventArgs(new Student(txtStudentNumber.Text, txtStudentFName.Text, txtStudentLName.Text, txtStudentEmail.Text)));
            AllowEditStudent(false);
        }

        /// <summary>
        /// Displays a dialog box that allows entry of student details
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void btnAddStudent_Click(object sender, EventArgs e) {
            //Create a UI for to collect student details
            UiAddStudent uiAddStudent = new UiAddStudent();
            uiAddStudent.Show();
            uiAddStudent.Student_Create += new EventHandler<StudentEventArgs>(CreateStudent);
        }

        /// <summary>
        /// Handles the creation of new students by child controls and fires them as events from this control
        /// </summary>
        /// <param name="sender">Child control</param>
        /// <param name="e">Student to be created</param>
        private void CreateStudent(object sender, StudentEventArgs e) {
            this.Student_Create.Invoke(this, e);
        }

        /// <summary>
        /// Displays the assets associated with the currently selected student loan.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridSelectedStudentsLoans_SelectionChanged(object sender, EventArgs e) {
            RefreshLoanAssetsDisplay();
        }

        /// <summary>
        /// Deletes the currently selected student from the model
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDeleteStudent_Click(object sender, EventArgs e) {
            //make sure a student was selected
            if (lstStudents.SelectedIndex >= 0) {
                Student del = studentList[lstStudents.SelectedItem.ToString()];
                //confirm that the student should be deleted
                if (MessageBox.Show("Are you sure you want to permanently remove '" + del.FirstName + " " + del.LastName + "' from the system? This process cannot be undone.", 
                    "Confirm Deletion of Student: " + del.StudentId , MessageBoxButtons.YesNo) == DialogResult.Yes) {
                        try {
                            this.Student_Delete.Invoke(this, new StudentEventArgs(del));
                        } catch (Exception delFail) {
                            MessageBox.Show(delFail.Message);
                        }
                }
            }
        }

        private void btn_ReturnLoan_Click(object sender, EventArgs e) {
            if (gridSelectedStudentsLoans.Rows.GetRowCount(DataGridViewElementStates.Selected) > 0) {
                //Check if the user wants to return this loan
                    DialogResult dialogResult = MessageBox.Show("Are you sure you want to return this loan? The operation cannot be undone.",
                        "Return Loan", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (dialogResult == DialogResult.Yes) {
                        Loan retLoan = loanList[Convert.ToInt32(gridSelectedStudentsLoans.SelectedRows[0].Cells["LoanNo"].Value)];
                        LoanEventArgs args = new LoanEventArgs(retLoan);
                        this.Loan_Return.Invoke(this, args);
                        RefreshLoansDisplay();
                    }
            }
        }

        private void btn_ReturnItem_Click(object sender, EventArgs e) {
            if (gridSelectedStudentsLoans.Rows.GetRowCount(DataGridViewElementStates.Selected) > 0 && gridSelectedLoansAssets.Rows.GetRowCount(DataGridViewElementStates.Selected) > 0) {
                //Check if the user wants to return this loan
                    DialogResult dialogResult = MessageBox.Show("Are you sure you want to return this loan? The operation cannot be undone.",
                        "Return Loan", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (dialogResult == DialogResult.Yes) {
                        Loan retLoan = loanList[Convert.ToInt32(gridSelectedStudentsLoans.SelectedRows[0].Cells["LoanNo"].Value)];
                        string assetId = (string)gridSelectedLoansAssets.SelectedRows[0].Cells["assetId"].Value;

                        LoanAssetEventArgs args = new LoanAssetEventArgs(retLoan, assetId);
                        this.LoanAsset_Return.Invoke(this, args);
                        RefreshLoansDisplay();
                    }
            }
        }

        private void btn_AddLoan_Click(object sender, EventArgs e) {
            UILoanEditor loanEdit = new UILoanEditor();
            //make sure a student was selected
            if (lstStudents.SelectedIndex >= 0) {
                Student stu = studentList[lstStudents.SelectedItem.ToString()];
                loanEdit.SetStudentId(stu.StudentId);
            }
            loanEdit.Show();
            loanEdit.FormClosing += new FormClosingEventHandler(loanEditorClosed);
        }

        private void loanEditorClosed(object sender, EventArgs e) {
            RefreshAll();
        }

        private void btn_UnHoldItem_Click(object sender, EventArgs e) {
            if(gridHold.Rows.GetRowCount(DataGridViewElementStates.Selected) > 0 && lstStudents.SelectedIndex >= 0){
                string studentId = lstStudents.SelectedItem.ToString();
                string assetId = (string)gridHold.SelectedRows[0].Cells["HoldAssetId"].Value;
                Hold del = new Hold(studentId, assetId);
                Hold_Delete(this, new HoldEventArgs(del));

                this.Holds_LoadAll(this, new EventArgs());
                lstStudents_SelectedIndexChanged(lstStudents, new EventArgs());
            }    
        }

        private void btn_RentItem_Click(object sender, EventArgs e) {
            if (gridHold.Rows.GetRowCount(DataGridViewElementStates.Selected) > 0 && lstStudents.SelectedIndex >= 0) {
                string status = (string)gridHold.SelectedRows[0].Cells["HoldStatus"].Value;
                if (status == "Available") {
                    string studentId = lstStudents.SelectedItem.ToString();
                    string assetId = (string)gridHold.SelectedRows[0].Cells["HoldAssetId"].Value;
                    
                    //try to loan the asset.
                    UILoanEditor loanEdit = new UILoanEditor();

                    loanEdit.SetStudentId(studentId);
                    loanEdit.MoveAssetToLoanList(assetId);

                    loanEdit.Show();
                    loanEdit.FormClosing += new FormClosingEventHandler(loanEditorClosed);

                    lstStudents_SelectedIndexChanged(lstStudents, new EventArgs());
                } else {
                    MessageBox.Show("The asset is currently on loan, it must be returned before it can be loaned again.");
                }
            }
        }

    }
}
